package com.buba.config;

import com.buba.system.pojo.SystemMenu;
import com.buba.system.pojo.SystemUser;
import com.buba.system.pojo.SystemUserRole;
import com.buba.system.service.LoginService;
import com.buba.system.service.MenuService;
import com.buba.system.service.RoleService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * @description: 自定义领域
 *  自定义realm实现 将认证/授权数据的来源转为数据库的实现
 * @Author: 游王子
 * @date: 2021/8/20 16:27
 */
public class CustomRealm extends AuthorizingRealm {
    private LoginService loginService;
    private RoleService roleService;
    private MenuService menuService;

    /**
     * 方法描述  授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取登录的信息的用户名称
        String userName = (String)principalCollection.getPrimaryPrincipal();
        SystemUser systemUser = new SystemUser();
        //通过set方法给用户名称赋值
        systemUser.setUserName(userName);

        // 一个账号可能存在多个角色
        //根据登录的账号名称查询角色表的名称
        Set<SystemUserRole> roles = roleService.selRoleByName(systemUser);
        Set<String> roleNames = new HashSet<>();
        Set<String> MenuNames = new HashSet<>();
        // 遍历角色获取角色名字
        roles.forEach(systemUserRole -> {
            // 将角色名添加的集合中
            roleNames.add(systemUserRole.getRoleName());//add方法是用来添加具体的类型
            // 一个角色可能拥有多个菜单权限
            // 根据角色名获取该角色拥有的菜单
            MenuNames.addAll(menuService.selRoleByRoleName(systemUserRole.getRoleName()));//addAll方法是用来添加集合的
        });
        // 创建授权类
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        // 授权角色
        simpleAuthorizationInfo.addRoles(roleNames);
        // 授权菜单
        simpleAuthorizationInfo.setStringPermissions(MenuNames);
        return simpleAuthorizationInfo;
    }

    /**
     * 方法描述 认证（也就是登录执行的方法）
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取登录的信息
        String userName = (String) authenticationToken.getPrincipal();
        if (userName == null || "".equals(userName.trim())) return null;
        // 通过帐号查询用户信息
        SystemUser systemUser = new SystemUser();
        systemUser.setUserName(userName);
        SystemUser login = loginService.login(systemUser);
        if (login.getUserPassword() == null) return null;
        // 这个是shiro主要进行认证的类
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, login.getUserPassword(), "customRealm");
        // 如果密码有盐值，需要在这加上
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("a"));
        return simpleAuthenticationInfo;
    }

    @Autowired
    @Qualifier("loginServiceImpl")
    public void setLoginService(LoginService loginService) {
        this.loginService = loginService;
    }

    @Autowired
    @Qualifier("roleServiceImpl")
    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }

    @Autowired
    @Qualifier("menuServiceImpl")
    public void setMenuService(MenuService menuService) {
        this.menuService = menuService;
    }
}
